package com.jwgf.smarowindingmachine_unity.logic;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.jwgf.Half485.modbusthreadpool.PLCData;
import com.jwgf.common.Utility;
import com.jwgf.fram.FramManager;
import com.jwgf.protocolstack.CommunicationStateListener.WriteFailedListener;
import com.jwgf.protocolstack.CommunicationStateListener.WriteSucceedListener;
import com.jwgf.protocolstack.ProtocolStack;
import com.jwgf.smarowindingmachine_unity.ui.SmaroWindingMachineActivity;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

public class FunctionSet {

    private static final String TAG = "FunctionSet";
    private static FunctionSet instance = new FunctionSet();
    private RunStopController controller = new RunStopController();

    private FunctionSet() {
        super();
    }

    public static FunctionSet getInstance() {
        return instance;
    }

    public void setAllSpindleAutoRunningOn() {
        controller.run();
    }

    public void setAllSpindleAutoRunningOff() {
        controller.stop();
    }

    public void setGroupAutoRunningOn(int group) {
        controller.run(group);
    }


    public static class RunState implements WriteSucceedListener, WriteFailedListener, RunStop {
        private RunStopController controller;
        private MachineParameterSharedPreference sp = MachineParameterSharedPreference.getInstance();

        @Override
        public void writeFailed(ProtocolStack ps, byte[] request) {
            next(request);
        }

        @Override
        public void writeSucceed(ProtocolStack ps, byte[] request) {
            next(request);
        }

        private void next(final byte[] request) {
            short index = (short) (request[2] & 0xff);
            int data = ((request[5] & 0xff) << 8) | (request[4] & 0xff);
            if (controller.getSpindleList().size() != 0) {
                if ((index == 0x30) && (data == 0x800)) {
                    final int spindle = controller.getSpindleList().remove();
                    new Handler(Looper.getMainLooper()).postDelayed((new Runnable() {

                        @Override
                        public void run() {
                            sendRunCmd(spindle);
                            Log.e(TAG, "单锭开启中：" + spindle);

                        }
                    }), 1500);
                }
            } else {
                SmaroWindingMachineActivity.canHandStack.putPriorityCmd(sp.releaseBroadcast());
                SmaroWindingMachineActivity.canHandStack.unregisterWriteFailedListener(this);
                SmaroWindingMachineActivity.canHandStack.unregisterWriteSucceedListener(this);
                controller.setState(new IdleState());
                Log.e(TAG, "所有单锭已开启！");
            }
        }

        @Override
        public void run(RunStopController controller) {
            this.controller = controller;
        }

        @Override
        public void stop(RunStopController controller) {
            Log.e(TAG, "开启过程中，发生停止！");
            this.controller = controller;
            SmaroWindingMachineActivity.canHandStack.unregisterWriteFailedListener(this);
            SmaroWindingMachineActivity.canHandStack.unregisterWriteSucceedListener(this);
            StopState stopState = new StopState();
            stopState.stop(controller);
            controller.setState(stopState);
            if (controller.getSpindleList().size() != 0) {
                SmaroWindingMachineActivity.canHandStack.registerWriteFailedListener(stopState);
                SmaroWindingMachineActivity.canHandStack.registerWriteSucceedListener(stopState);
                SmaroWindingMachineActivity.canHandStack.putPriorityCmd(sp.getBroadcast());
                int spindle = controller.getSpindleList().remove();
                sendStopCmd(spindle);
                Log.e(TAG, "单锭停止中：" + spindle);
            }
        }

    }

    public static class StopState implements WriteSucceedListener, WriteFailedListener, RunStop {
        private RunStopController controller;
        private MachineParameterSharedPreference sp = MachineParameterSharedPreference.getInstance();

        @Override
        public void writeFailed(ProtocolStack ps, byte[] request) {
            next(request);
        }

        @Override
        public void writeSucceed(ProtocolStack ps, byte[] request) {
            next(request);
        }

        @Override
        public void run(RunStopController controller) {
            Log.e(TAG, "停止过程中，发生开启！");
            this.controller = controller;
            SmaroWindingMachineActivity.canHandStack.unregisterWriteFailedListener(this);
            SmaroWindingMachineActivity.canHandStack.unregisterWriteSucceedListener(this);
            RunState runState = new RunState();
            runState.run(controller);
            controller.setState(runState);
            if (controller.getSpindleList().size() != 0) {
                SmaroWindingMachineActivity.canHandStack.registerWriteFailedListener(runState);
                SmaroWindingMachineActivity.canHandStack.registerWriteSucceedListener(runState);
                SmaroWindingMachineActivity.canHandStack.putPriorityCmd(sp.getBroadcast());
                int spindle = controller.getSpindleList().remove();
                sendRunCmd(spindle);
                Log.e(TAG, "单锭开启中：" + spindle);
            }
        }

        @Override
        public void stop(RunStopController controller) {
            this.controller = controller;
        }

        private void next(final byte[] request) {
            short index = (short) (request[2] & 0xff);
            int dataDB = ((request[5] & 0xff) << 8) | (request[4] & 0xff);
            int dataDC = ((request[7] & 0xff) << 8) | (request[6] & 0xff);
            if (controller.getSpindleList().size() != 0) {
                if ((index == 0x30) && (dataDB == 0x1000) ) {
                    final int spindle = controller.getSpindleList().remove();
                    new Handler(Looper.getMainLooper()).postDelayed((new Runnable() {

                        @Override
                        public void run() {
                            Log.e(TAG, "单锭停止中：" + spindle);
                            sendNormalStopCmd(spindle);
                        }
                    }), 500);
                } else if ((index == 0x30) && (dataDC == 1)){
                    final int spindle = controller.getSpindleList().remove();
                    new Handler(Looper.getMainLooper()).postDelayed((new Runnable() {

                        @Override
                        public void run() {
                            Log.e(TAG, "单锭停止中：" + spindle);
                            sendCutStopCmd(spindle);
                        }
                    }), 500);
                }
            } else {
                SmaroWindingMachineActivity.canHandStack.putPriorityCmd(sp.releaseBroadcast());
                SmaroWindingMachineActivity.canHandStack.unregisterWriteFailedListener(this);
                SmaroWindingMachineActivity.canHandStack.unregisterWriteSucceedListener(this);
                controller.setState(new IdleState());
                Log.e(TAG, "所有单锭已停止！");

            }
        }
    }


    public static class IdleState implements RunStop {
        private MachineParameterSharedPreference sp = MachineParameterSharedPreference.getInstance();

        @Override
        public void run(RunStopController controller) {
            RunState runState = new RunState();
            controller.setState(runState);
            runState.run(controller);
            if (controller.getSpindleList().size() != 0) {
                SmaroWindingMachineActivity.canHandStack.registerWriteFailedListener(runState);
                SmaroWindingMachineActivity.canHandStack.registerWriteSucceedListener(runState);
                SmaroWindingMachineActivity.canHandStack.putPriorityCmd(sp.getBroadcast());
                int spindle = controller.getSpindleList().remove();
                sendRunCmd(spindle);
                Log.e(TAG, "单锭开启中：" + spindle);
            }
        }

        @Override
        public void stop(RunStopController controller) {
            StopState stopState = new StopState();
            controller.setState(stopState);
            stopState.stop(controller);
            if (controller.getSpindleList().size() != 0) {
                SmaroWindingMachineActivity.canHandStack.registerWriteFailedListener(stopState);
                SmaroWindingMachineActivity.canHandStack.registerWriteSucceedListener(stopState);
                SmaroWindingMachineActivity.canHandStack.putPriorityCmd(sp.getBroadcast());
                int spindle = controller.getSpindleList().remove();
                sendStopCmd(spindle);
                Log.e(TAG, "单锭停止中：" + spindle);
            }

        }

    }

    public static void sendRunCmd(int spindle) {
        SmaroWindingMachineActivity.canHandStack
                .putPriorityCmd(CanCommand.createSpindleCmdFunction(spindle, 0x30, 0x800, 0));
    }

    public static void sendStopCmd(int spindle) {
        MachineParameterSharedPreference sp = MachineParameterSharedPreference.getInstance();
        int stop_type = Integer.parseInt(sp.getValue(MachineParameterSharedPreference.STOP_TYPE, "0"));
        boolean vd140_bit4 = Utility.BitUtils.getBitValue(PLCData.getInstance().getHoldingRegister(1, 70), 4);
        if (vd140_bit4) {
            SmaroWindingMachineActivity.canHandStack
                    .putPriorityCmd(CanCommand.createSpindleCmdFunction(spindle, 0x30, 0, 1));
        } else {
            if (stop_type == 0) {
                SmaroWindingMachineActivity.canHandStack
                        .putPriorityCmd(CanCommand.createSpindleCmdFunction(spindle, 0x30, 0x1000, 0));
            } else {
                SmaroWindingMachineActivity.canHandStack
                        .putPriorityCmd(CanCommand.createSpindleCmdFunction(spindle, 0x30, 0, 1));
            }
        }
    }

    public static void sendNormalStopCmd(int spindle) {
        SmaroWindingMachineActivity.canHandStack
                .putPriorityCmd(CanCommand.createSpindleCmdFunction(spindle, 0x30, 0x1000, 0));
    }

    public static void sendCutStopCmd(int spindle) {
        SmaroWindingMachineActivity.canHandStack
                .putPriorityCmd(CanCommand.createSpindleCmdFunction(spindle, 0x30, 0, 1));
    }

    public static interface RunStop {
        void run(RunStopController controller);

        void stop(RunStopController controller);
    }

    public static class RunStopController {
        private RunStop state = new IdleState();
        private LinkedList<Integer> spindleList = new LinkedList<>();
        private Set<Integer> runTaskGroup = new HashSet<>();

        public void setState(RunStop state) {
            this.state = state;
            // 当状态为IdleState时，从队列中取任务执行
            if (state instanceof IdleState) {
                if (!runTaskGroup.isEmpty()) {
                    int group = runTaskGroup.iterator().next();
                    run(group);
                    runTaskGroup.remove(group);
                }
            }
        }

        public LinkedList<Integer> getSpindleList() {
            return spindleList;
        }

        public void run() {
            runTaskGroup.clear();
            spindleList.clear();
            int beginSpindle = 1;
            int endSpindle = Integer.valueOf(MachineParameterSharedPreference.getInstance().getValue(0x29, 0x01));
            for (int spindle = beginSpindle; spindle <= endSpindle; ++spindle) {
                spindleList.add(spindle);
            }
            state.run(this);
        }

        //被连续调用时，将任务缓存到队列，在state为IdleState时，执行下一个任务
        public void run(int group) {
            int begin = group * 8 - 7;
            int end = group * 8;
            if (state instanceof IdleState) {
                for (int spindle = begin; spindle <= end; ++spindle) {
                    String key1 = spindle + "-" + 0x63 + "-" + 1;
                    if ((FramManager.getInstance().getInt(key1, 0) & 0x10) != 0) {
                        spindleList.add(spindle);
                    }
                }
                state.run(this);
            } else {
                runTaskGroup.add(group);
            }
        }

        public void stop() {
            runTaskGroup.clear();
            spindleList.clear();
            int beginSpindle = 1;
            int endSpindle = Integer.valueOf(MachineParameterSharedPreference.getInstance().getValue(0x29, 0x01));
            for (int spindle = beginSpindle; spindle <= endSpindle; ++spindle) {
                spindleList.add(spindle);
            }
            state.stop(this);
        }

    }
}
